export function treeFind<
  N extends string,
  T extends { [name in N]?: T[] }
>(
  trees: T[],
  cname: N,
  judge: (item: T, index: number) => boolean
): T | null {
  for (let i = 0; i < trees.length; i++) {
    const item = trees[i];
    if (judge(item, i)) {
      return item;
    } else {
      const children = item[cname];
      if (children) {
        const findCild = treeFind(children as T[], cname, judge);
        if (findCild) {
          return findCild;
        }
      }
    }
  }
  return null;
}

export function treeForeach<
  N extends string,
  T extends { [name in N]?: T[] }
>(
  trees: T[],
  cname: N,
  callback: (item: T, index: number) => void
): void {
  for (let i = 0; i < trees.length; i++) {
    const item = trees[i];
    callback(item, i);
    const children = item[cname];
    if (children) {
      treeForeach(children as T[], cname, callback);
    }
  }
}

export function treeCopy<N extends string, T extends { [name in N]?: T[] }>(trees: T[], cname: N): T[] {
  return trees.map(item => {
    const newItem = { ...item };
    const children = newItem[cname];
    if (children) {
      newItem[cname] = treeCopy(children as T[], cname) as T[N];
    }
    return newItem;
  });
}

/** 交换树 */
export function treeSwap<T, K>(
  data: T,
  getKey: (item: T) => K,
  getChildren: (item: T) => T[],
  fromParentId: K,
  fromIndex: number,
  toParentId: K,
  toIndex: number,
) {
  const map: Map<K, T[]> = new Map();
  function foreachSet(item: T) {
    const key = getKey(item);
    const children = getChildren(item);
    map.set(key, children);
    if (children) {
      for (const child of children) {
        foreachSet(child);
      }
    }
  }
  foreachSet(data);
  const item = map.get(fromParentId).splice(fromIndex, 1);
  map.get(toParentId).splice(toIndex, 0, ...item);
}
